package org.example.base.redis;

import lombok.extern.slf4j.Slf4j;
import org.example.exceptions.BusinessException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.Set;
import java.util.concurrent.TimeUnit;

import static org.example.enums.ErrorCodeEnum.REDIS_EXE_EXCEPTION;

@Service
@Slf4j
public class RedisBaseService<K, V> {

    @Resource(name = "customRedisTemplate")
    @Lazy
    private RedisTemplate<K, V> redisTemplate;

    /**
     * 设置键值对
     *
     * @param key   键
     * @param value 值
     */
    public void set(K key, V value) {
        try {
            redisTemplate.opsForValue().set(key, value);
        } catch (Exception e) {
            throw handleRedisException(e, "Error while setting key-value pair");
        }
    }

    /**
     * 获取指定键的值
     *
     * @param key 键
     * @return 值
     */
    public V get(K key) {
        try {
            return redisTemplate.opsForValue().get(key);
        } catch (Exception e) {
            throw handleRedisException(e, "Error while getting value for key: " + key);
        }
    }

    /**
     * 删除指定键
     *
     * @param key 键
     */
    public void delete(K key) {
        try {
            redisTemplate.delete(key);
        } catch (Exception e) {
            throw handleRedisException(e, "Error while deleting key: " + key);
        }
    }

    /**
     * 设置键值对并设置过期时间
     *
     * @param key     键
     * @param value   值
     * @param timeout 过期时间
     * @param unit    时间单位
     */
    public void setWithExpire(K key, V value, long timeout, TimeUnit unit) {
        try {
            redisTemplate.opsForValue().set(key, value, timeout, unit);
        } catch (Exception e) {
            throw handleRedisException(e, "Error while setting key-value pair with expiration");
        }
    }

    /**
     * 在哈希中设置字段值
     *
     * @param key     哈希键
     * @param hashKey 哈希字段
     * @param value   值
     */
    public void hSet(K key, K hashKey, V value) {
        try {
            redisTemplate.opsForHash().put(key, hashKey, value);
        } catch (Exception e) {
            throw handleRedisException(e, "Error while setting hash field-value pair");
        }
    }

    /**
     * 从哈希中获取字段值
     *
     * @param key     哈希键
     * @param hashKey 哈希字段
     * @return 值
     */
    public V hGet(K key, K hashKey) {
        try {
            return (V) redisTemplate.opsForHash().get(key, hashKey);
        } catch (Exception e) {
            throw  handleRedisException(e, "Error while getting hash field value");
        }
    }

    /**
     * 删除哈希中的字段
     *
     * @param key      哈希键
     * @param hashKeys 哈希字段
     */
    public void hDelete(K key, K... hashKeys) {
        try {
            redisTemplate.opsForHash().delete(key, (Object[]) hashKeys);
        } catch (Exception e) {
            throw handleRedisException(e, "Error while deleting hash fields");
        }
    }

    /**
     * 向列表左侧添加元素
     *
     * @param key    列表键
     * @param values 元素值
     */
    public void lPush(K key, V... values) {
        try {
            redisTemplate.opsForList().leftPushAll(key, values);
        } catch (Exception e) {
            throw handleRedisException(e, "Error while pushing elements to list");
        }
    }

    /**
     * 从列表右侧弹出元素
     *
     * @param key 列表键
     * @return 弹出的元素
     */
    public V rPop(K key) {
        try {
            return redisTemplate.opsForList().rightPop(key);
        } catch (Exception e) {
            throw handleRedisException(e, "Error while popping element from list");
        }
    }

    /**
     * 添加元素到集合
     *
     * @param key    集合键
     * @param values 元素值
     */
    public void sAdd(K key, V... values) {
        try {
            redisTemplate.opsForSet().add(key, values);
        } catch (Exception e) {
            throw handleRedisException(e, "Error while adding elements to set");
        }
    }

    /**
     * 获取集合中的所有成员
     *
     * @param key 集合键
     * @return 成员列表
     */
    public Set<V> sMembers(K key) {
        try {
            return redisTemplate.opsForSet().members(key);
        } catch (Exception e) {
            throw handleRedisException(e, "Error while getting set members");
        }
    }

    /**
     * 处理 Redis 异常
     *
     * @param e       异常对象
     * @param message 错误信息
     */
    private BusinessException handleRedisException(Exception e, String message) {
        log.error("redis exception:{}", message);
        return new BusinessException(REDIS_EXE_EXCEPTION, e);
    }
}